package uqbar.comm;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SerialPort extends AbstractPort implements SerialPortEventListener {

	private CommPortIdentifier portIdentifier;

	private gnu.io.SerialPort serialPort;
	private InputStream input;
	private OutputStream output;

	/** Milliseconds to block while waiting for port open */
	private int timeOut = 2000;
	/** Default bits per second for COM port. */
	private int dataRate = 9600;

	public SerialPort(final CommPortIdentifier portIdentifier) {
		this.portIdentifier = portIdentifier;
	}

	public SerialPort(final String portName) {
		this(findPort(portName));
	}

	private static CommPortIdentifier findPort(final String portName) {
		try {
			return CommPortIdentifier.getPortIdentifier(portName);
		} catch (Exception e) {
			throw ProgramException.wrap(e);
		}
	}

	public SerialPort() {
		this(CommonsPortNames.find());
	}

	@Override
	public void close() {
		this.serialPort.close();
	}

	@Override
	public void open() {
		try {
			this.serialPort = (gnu.io.SerialPort) this.getPortIdentifier().open(this.getClass().getName(),
					this.getTimeOut());

			// set port parameters
			this.serialPort.setSerialPortParams(this.getDataRate(), gnu.io.SerialPort.DATABITS_8,
					gnu.io.SerialPort.STOPBITS_1, gnu.io.SerialPort.PARITY_NONE);

			this.serialPort.addEventListener(this);
		} catch (Exception e) {
			throw ProgramException.wrap(e);
		}

	}

	public int getTimeOut() {
		return this.timeOut;
	}

	public int getDataRate() {
		return this.dataRate;
	}

	public void setDataRate(final int dataRate) {
		this.dataRate = dataRate;
	}

	public void setTimeOut(final int timeOut) {
		this.timeOut = timeOut;
	}

	protected CommPortIdentifier getPortIdentifier() {
		return this.portIdentifier;
	}

	@Override
	public InputStream getInputStream() {
		try {
			return this.serialPort.getInputStream();
		} catch (IOException e) {
			throw ProgramException.wrap(e);
		}
	}

	@Override
	public OutputStream getOutputStream() {
		try {
			return this.serialPort.getOutputStream();
		} catch (IOException e) {
			throw ProgramException.wrap(e);
		}
	}

	@Override
	public void serialEvent(final SerialPortEvent arg0) {
		if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
			this.notifyDataAvailable();
		} else {
			System.out.println("SerialPortEvent no manejado: " + arg0.getEventType());
		}
	}
}
